///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once

#ifndef __Technique_H__
#define __Technique_H__

#include "OgrePrerequisites.h"
#include "OgreIteratorWrappers.h"
#include "OgreBlendMode.h"
#include "OgreCommon.h"
#include "OgrePass.h"
#include "OgreIteratorWrappers.h"
#include "OgreRenderSystemCapabilities.h"
#include "OgreUserObjectBindings.h"

namespace Ogre {
	
	
	
	class _OgreExport Technique : public MemAlloc_Resource
    {
    protected:
        // illumination pass state type
        enum IlluminationPassesState
        {
            IPS_COMPILE_DISABLED = -1,
            IPS_NOT_COMPILED = 0,
            IPS_COMPILED = 1
        };

        typedef vector<Pass*>::type Passes;
        /// List of primary passes
        Passes mPasses;
        /// List of derived passes, categorised into IlluminationStage (ordered)
        IlluminationPassList mIlluminationPasses;
        Material* mParent; // raw pointer since we don't want child to stop parent's destruction
        bool mIsSupported;
        IlluminationPassesState mIlluminationPassesCompilationPhase;
		/// LOD level
        unsigned short mLodIndex;
		
		unsigned short mSchemeIndex;
        String mName; // optional name for the technique

        /// Internal method for clearing illumination pass list
        void clearIlluminationPasses(void);
		/// Internal method - check for manually assigned illumination passes
		bool checkManuallyOrganisedIlluminationPasses();


		
		MaterialPtr mShadowCasterMaterial;
		
		String mShadowCasterMaterialName;
		
		MaterialPtr mShadowReceiverMaterial;
		
		String mShadowReceiverMaterialName;	

		// User objects binding.
		UserObjectBindings	mUserObjectBindings;

	public:
		
		enum IncludeOrExclude
		{
			/// Inclusive - only support if present
			INCLUDE = 0,
			/// Exclusive - do not support if present
			EXCLUDE = 1
		};
		/// Rule controlling whether technique is deemed supported based on GPU vendor
		struct GPUVendorRule
		{
			GPUVendor vendor;
			IncludeOrExclude includeOrExclude;
			GPUVendorRule()
				: vendor(GPU_UNKNOWN), includeOrExclude(EXCLUDE) {}
			GPUVendorRule(GPUVendor v, IncludeOrExclude ie)
				: vendor(v), includeOrExclude(ie) {}
		};
		/// Rule controlling whether technique is deemed supported based on GPU device name
		struct GPUDeviceNameRule
		{
			String devicePattern;
			IncludeOrExclude includeOrExclude;
			bool caseSensitive;
			GPUDeviceNameRule()
				: includeOrExclude(EXCLUDE), caseSensitive(false) {}
			GPUDeviceNameRule(const String& pattern, IncludeOrExclude ie, bool caseSen)
				: devicePattern(pattern), includeOrExclude(ie), caseSensitive(caseSen) {}
		};
		typedef vector<GPUVendorRule>::type GPUVendorRuleList;
		typedef vector<GPUDeviceNameRule>::type GPUDeviceNameRuleList;
	protected:
		GPUVendorRuleList mGPUVendorRules;
		GPUDeviceNameRuleList mGPUDeviceNameRules;
	public:
        /// Constructor
        Technique(Material* parent);
        /// Copy constructor
        Technique(Material* parent, const Technique& oth);
        ~Technique();
        
        bool isSupported(void) const;
        
        String _compile(bool autoManageTextureUnits);
		/// Internal method for checking GPU vendor / device rules
		bool checkGPURules(StringUtil::StrStreamType& errors);
		/// Internal method for checking hardware support
		bool checkHardwareSupport(bool autoManageTextureUnits, StringUtil::StrStreamType& compileErrors);
                
        void _compileIlluminationPasses(void);


        
        Pass* createPass(void);
        
        Pass* getPass(unsigned short index);
        
        Pass* getPass(const String& name);
        
        unsigned short getNumPasses(void) const;
        
        void removePass(unsigned short index);
        
        void removeAllPasses(void);
        
        bool movePass(const unsigned short sourceIndex, const unsigned short destinationIndex);
        typedef VectorIterator<Passes> PassIterator;
        
        const PassIterator getPassIterator(void);
        typedef VectorIterator<IlluminationPassList> IlluminationPassIterator;
        
        const IlluminationPassIterator getIlluminationPassIterator(void);
        /// Gets the parent Material
        Material* getParent(void) const { return mParent; }

        
        Technique& operator=(const Technique& rhs);

		/// Gets the resource group of the ultimate parent Material
		const String& getResourceGroup(void) const;

		
		bool isTransparent(void) const;

		
		bool isTransparentSortingEnabled(void) const;

		
		bool isTransparentSortingForced(void) const;

        
        void _prepare(void);
        
        void _unprepare(void);
        
        void _load(void);
        
        void _unload(void);

        // Is this loaded?
        bool isLoaded(void) const;

        
        void _notifyNeedsRecompile(void);

		
		Ogre::MaterialPtr getShadowCasterMaterial() const;
		
		void setShadowCasterMaterial(Ogre::MaterialPtr val);
		
		void setShadowCasterMaterial(const Ogre::String &name);
		
		Ogre::MaterialPtr getShadowReceiverMaterial() const;
		
		void setShadowReceiverMaterial(Ogre::MaterialPtr val);
		
		void setShadowReceiverMaterial(const Ogre::String &name);

        // -------------------------------------------------------------------------------
        // The following methods are to make migration from previous versions simpler
        // and to make code easier to write when dealing with simple materials
        // They set the properties which have been moved to Pass for all Techniques and all Passes

        
        void setPointSize(Real ps);

        
        void setAmbient(Real red, Real green, Real blue);

        
        void setAmbient(const ColourValue& ambient);

        
        void setDiffuse(Real red, Real green, Real blue, Real alpha);

        
        void setDiffuse(const ColourValue& diffuse);

        
        void setSpecular(Real red, Real green, Real blue, Real alpha);

        
        void setSpecular(const ColourValue& specular);

        
        void setShininess(Real val);

        
        void setSelfIllumination(Real red, Real green, Real blue);

        
        void setSelfIllumination(const ColourValue& selfIllum);

		
        void setDepthCheckEnabled(bool enabled);

        
        void setDepthWriteEnabled(bool enabled);

        
        void setDepthFunction( CompareFunction func );

		
		void setColourWriteEnabled(bool enabled);

        
        void setCullingMode( CullingMode mode );

        
        void setManualCullingMode( ManualCullingMode mode );

        
        void setLightingEnabled(bool enabled);

        
        void setShadingMode( ShadeOptions mode );

        
        void setFog(
            bool overrideScene,
            FogMode mode = FOG_NONE,
            const ColourValue& colour = ColourValue::White,
            Real expDensity = 0.001, Real linearStart = 0.0, Real linearEnd = 1.0 );

        
        void setDepthBias(float constantBias, float slopeScaleBias);

        
        void setTextureFiltering(TextureFilterOptions filterType);
        
        void setTextureAnisotropy(unsigned int maxAniso);

        
        void setSceneBlending( const SceneBlendType sbt );

        
        void setSeparateSceneBlending( const SceneBlendType sbt, const SceneBlendType sbta );

        
        void setSceneBlending( const SceneBlendFactor sourceFactor, const SceneBlendFactor destFactor);

        
        void setSeparateSceneBlending( const SceneBlendFactor sourceFactor, const SceneBlendFactor destFactor, const SceneBlendFactor sourceFactorAlpha, const SceneBlendFactor destFactorAlpha);

        
        void setLodIndex(unsigned short index);
        
        unsigned short getLodIndex(void) const { return mLodIndex; }

		
		void setSchemeName(const String& schemeName);
		
		const String& getSchemeName(void) const;
		
		/// Internal method for getting the scheme index
		unsigned short _getSchemeIndex(void) const;
		   	
        
        bool isDepthWriteEnabled(void) const;

        
        bool isDepthCheckEnabled(void) const;

        
        bool hasColourWriteDisabled(void) const;

        
        void setName(const String& name);
        /// Gets the name of the technique
        const String& getName(void) const { return mName; }

        
        bool applyTextureAliases(const AliasTextureNamePairList& aliasList, const bool apply = true) const;


		
		void addGPUVendorRule(GPUVendor vendor, IncludeOrExclude includeOrExclude);
		
		void addGPUVendorRule(const GPUVendorRule& rule);
		
		void removeGPUVendorRule(GPUVendor vendor);
		typedef ConstVectorIterator<GPUVendorRuleList> GPUVendorRuleIterator;
		/// Get an iterator over the currently registered vendor rules.
		GPUVendorRuleIterator getGPUVendorRuleIterator() const;

		
		void addGPUDeviceNameRule(const String& devicePattern, IncludeOrExclude includeOrExclude, bool caseSensitive = false);
		
		void addGPUDeviceNameRule(const GPUDeviceNameRule& rule);
		
		void removeGPUDeviceNameRule(const String& devicePattern);
		typedef ConstVectorIterator<GPUDeviceNameRuleList> GPUDeviceNameRuleIterator;
		/// Get an iterator over the currently registered device name rules.
		GPUDeviceNameRuleIterator getGPUDeviceNameRuleIterator() const;

		
		UserObjectBindings&	getUserObjectBindings() { return mUserObjectBindings; }

		
		const UserObjectBindings& getUserObjectBindings() const { return mUserObjectBindings; }

    };

	
	

}
#endif
